#include "UniverseTest.h"

#include "../src/pw_exception.h"

CPPUNIT_TEST_SUITE_REGISTRATION(UniverseTest);

using physicsworks::math::vec3;
using physicsworks::exception::BadArg;
using physicsworks::exception::WorldAlreadyAdded;
using physicsworks::exception::UnkownWorld;
using physicsworks::exception::WorldBodyAlreadyAdded;

void UniverseTest::setUp()
{
	universe = instanceUniverse();
	
	mesh = new BodyMesh("tests/data/monkey.mesh.xml");
}

void UniverseTest::testStartStopInstancingObjects()
{
	World* world;
	Body *body, *sphere, *cube, *box;
	
	SpatialPartitioningType s = physicsworks::NULL_SPATIAL_PARTITIONING;
    NullSpatialPartitioningConfig sc;
    
	world = universe->instanceWorld(-100, -100, -100, 200, 200, 200, s, sc);
	body = universe->instanceBody(mesh->vertX, mesh->vertY, mesh->vertZ, mesh->numVertices, mesh->verticesIndices, mesh->numFaces);
	sphere = universe->instanceSphereBody(2);
	cube = universe->instanceCubeBody(2);
	box = universe->instanceBoxBody(3, 1, 1);
	
	CPPUNIT_ASSERT( world != 0 );
	CPPUNIT_ASSERT( body != 0 );
	CPPUNIT_ASSERT( sphere != 0 );
	CPPUNIT_ASSERT( cube != 0 );
	CPPUNIT_ASSERT( box != 0 );
	
	delete world;
	delete body;
	delete sphere;
	delete cube;
	delete box;
	
	CPPUNIT_ASSERT_THROW(universe->instanceWorld(-100, -100, -100, -100,  200,  200, s, sc), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceWorld(-100, -100, -100,  200, -100,  200, s, sc), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceWorld(-100, -100, -100,  200,  200, -100, s, sc), BadArg);
	
	CPPUNIT_ASSERT_THROW(universe->instanceBody(mesh->vertX, mesh->vertY, mesh->vertZ, 2, mesh->verticesIndices, mesh->numFaces), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceBody(mesh->vertX, mesh->vertY, mesh->vertZ, mesh->numVertices, mesh->verticesIndices, 0), BadArg);
	
	CPPUNIT_ASSERT_THROW(universe->instanceSphereBody(0), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceCubeBody(0), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceSphereBody(-5), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceCubeBody(-5), BadArg);
	
	CPPUNIT_ASSERT_THROW(universe->instanceBoxBody(0, 0, 0), BadArg);
	CPPUNIT_ASSERT_THROW(universe->instanceBoxBody(-2, 0, 0), BadArg);
}

void UniverseTest::testAddingRemovingWorlds()
{
	SpatialPartitioningType s = physicsworks::NULL_SPATIAL_PARTITIONING;
    NullSpatialPartitioningConfig sc;

	World* world0 = universe->instanceWorld(-100, -100, -100, 200, 200, 200, s, sc);
	World* world1 = universe->instanceWorld(-50, -100, -100, 200, 200, 210, s, sc);
	World* world2 = universe->instanceWorld(-100, -100, -30, 200, 200, 250, s, sc);
	
	universe->add(world0);
	universe->add(world1);
	universe->add(world2);
	universe->remove(world2);
	universe->add(world2);
	
	CPPUNIT_ASSERT_THROW(universe->add(world0), WorldAlreadyAdded);
	CPPUNIT_ASSERT_THROW(universe->add(0), BadArg);
	CPPUNIT_ASSERT_THROW(universe->remove(0), BadArg);
	universe->remove(world2);
	CPPUNIT_ASSERT_THROW(universe->remove(world2), UnkownWorld);
	
	Body *body, *sphere;
	
	body = universe->instanceBody(mesh->vertX, mesh->vertY, mesh->vertZ, mesh->numVertices, mesh->verticesIndices, mesh->numFaces);
	sphere = universe->instanceSphereBody(2);
	
	world0->add(body);
	world0->add(sphere);
	
	universe->remove(world0);
	world1->add(body);
	
	CPPUNIT_ASSERT_THROW(universe->add(world0), WorldBodyAlreadyAdded);
	
	universe->removeAll();
	
	delete world0;
	delete world1;
	delete world2;
	delete body;
	delete sphere;
}

void UniverseTest::testGetWorldsList()
{
	SpatialPartitioningType s = physicsworks::NULL_SPATIAL_PARTITIONING;
    NullSpatialPartitioningConfig sc;

	World* world0 = universe->instanceWorld(-100, -100, -100, 200, 200, 200, s, sc);
	World* world1 = universe->instanceWorld(-50, -100, -100, 200, 200, 210, s, sc);
	World* world2 = universe->instanceWorld(-100, -100, -30, 200, 200, 250, s, sc);
	
	int size;
	CPPUNIT_ASSERT(universe->getWorldsList(&size) == 0);
	
	universe->add(world0);
	universe->add(world1);
	universe->remove(world0);
	universe->add(world2);
	
	World** wl = universe->getWorldsList(&size);
	CPPUNIT_ASSERT(size == 2);
	CPPUNIT_ASSERT( (wl[0] == world1 && wl[1] == world2) ^ (wl[0] == world2 && wl[1] == world1) );
	universe->removeAll();
	
	delete world0;
	delete world1;
	delete world2;
	delete [] wl;
}

void UniverseTest::tearDown()
{
	destroyUniverse();
	delete mesh;
}
